/*
* Copyright (C) 1997-2001 Id Software, Inc.
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.
* 
* See the GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*  
*/

// Created on 01.11.2003 by RST.

// $Id: GameUtil.java,v 1.15 2005/12/27 21:02:31 salomo Exp $
using System;
using Defines = Suake2.UI.Defines;
using Globals = Suake2.UI.Globals;
using M = Suake2.UI.client.M;
using Com = Suake2.UI.qcommon.Com;
using Lib = Suake2.UI.util.Lib;
using Math3D = Suake2.UI.util.Math3D;
namespace Suake2.UI.game
{
	
	public class GameUtil
	{
		public class AnonymousClassEntThinkAdapter:EntThinkAdapter
		{
			override public System.String ID
			{
				get
				{
					return "Think_Delay";
				}
				
			}
			public override bool think(edict_t ent)
			{
				jake2.game.GameUtil.G_UseTargets(ent, ent.activator);
				jake2.game.GameUtil.G_FreeEdict(ent);
				return true;
			}
		}
		public class AnonymousClassEntThinkAdapter1:EntThinkAdapter
		{
			override public System.String ID
			{
				get
				{
					return "G_FreeEdictA";
				}
				
			}
			public override bool think(edict_t ent)
			{
				jake2.game.GameUtil.G_FreeEdict(ent);
				return false;
			}
		}
		public class AnonymousClassEntThinkAdapter2:EntThinkAdapter
		{
			override public System.String ID
			{
				get
				{
					return "MegaHealth_think";
				}
				
			}
			public override bool think(edict_t self)
			{
				if (self.owner.health > self.owner.max_health)
				{
					self.nextthink = GameBase.level.time + 1;
					self.owner.health -= 1;
					return false;
				}
				
				if (!((self.spawnflags & Defines.DROPPED_ITEM) != 0) && (GameBase.deathmatch.value_Renamed != 0))
					GameItems.SetRespawn(self, 20);
				else
					jake2.game.GameUtil.G_FreeEdict(self);
				
				return false;
			}
		}
		public class AnonymousClassEntThinkAdapter3:EntThinkAdapter
		{
			override public System.String ID
			{
				get
				{
					return "M_CheckAttack";
				}
				
			}
			
			public override bool think(edict_t self)
			{
				float[] spot1 = new float[]{0, 0, 0};
				
				float[] spot2 = new float[]{0, 0, 0};
				float chance;
				trace_t tr;
				
				if (self.enemy.health > 0)
				{
					// see if any entities are in the way of the shot
					Math3D.VectorCopy(self.s.origin, spot1);
					spot1[2] += self.viewheight;
					Math3D.VectorCopy(self.enemy.s.origin, spot2);
					spot2[2] += self.enemy.viewheight;
					
					tr = GameBase.gi.trace(spot1, null, null, spot2, self, Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER | Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA | Defines.CONTENTS_WINDOW);
					
					// do we have a clear shot?
					if (tr.ent != self.enemy)
						return false;
				}
				
				// melee attack
				if (GameAI.enemy_range == Defines.RANGE_MELEE)
				{
					// don't always melee in easy mode
					if (GameBase.skill.value_Renamed == 0 && (Lib.rand() & 3) != 0)
						return false;
					if (self.monsterinfo.melee != null)
						self.monsterinfo.attack_state = Defines.AS_MELEE;
					else
						self.monsterinfo.attack_state = Defines.AS_MISSILE;
					return true;
				}
				
				// missile attack
				if (self.monsterinfo.attack == null)
					return false;
				
				if (GameBase.level.time < self.monsterinfo.attack_finished)
					return false;
				
				if (GameAI.enemy_range == Defines.RANGE_FAR)
					return false;
				
				if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0)
				{
					chance = 0.4f;
				}
				else if (GameAI.enemy_range == Defines.RANGE_MELEE)
				{
					chance = 0.2f;
				}
				else if (GameAI.enemy_range == Defines.RANGE_NEAR)
				{
					chance = 0.1f;
				}
				else if (GameAI.enemy_range == Defines.RANGE_MID)
				{
					chance = 0.02f;
				}
				else
				{
					return false;
				}
				
				if (GameBase.skill.value_Renamed == 0)
					chance = (float) (chance * 0.5);
				else if (GameBase.skill.value_Renamed >= 2)
					chance *= 2;
				
				if (Lib.random() < chance)
				{
					self.monsterinfo.attack_state = Defines.AS_MISSILE;
					self.monsterinfo.attack_finished = GameBase.level.time + 2 * Lib.random();
					return true;
				}
				
				if ((self.flags & Defines.FL_FLY) != 0)
				{
					if (Lib.random() < 0.3f)
						self.monsterinfo.attack_state = Defines.AS_SLIDING;
					else
						self.monsterinfo.attack_state = Defines.AS_STRAIGHT;
				}
				
				return false;
			}
		}
		public class AnonymousClassEntUseAdapter:EntUseAdapter
		{
			override public System.String ID
			{
				get
				{
					return "monster_use";
				}
				
			}
			public override void  use(edict_t self, edict_t other, edict_t activator)
			{
				if (self.enemy != null)
					return ;
				if (self.health <= 0)
					return ;
				if ((activator.flags & Defines.FL_NOTARGET) != 0)
					return ;
				if ((null == activator.client) && 0 == (activator.monsterinfo.aiflags & Defines.AI_GOOD_GUY))
					return ;
				
				// delay reaction so if the monster is teleported, its sound is
				// still heard
				self.enemy = activator;
				jake2.game.GameUtil.FoundTarget(self);
			}
		}
		
		public static void  checkClassname(edict_t ent)
		{
			
			if (ent.classname == null)
			{
				Com.Printf("edict with classname = null: " + ent.index);
			}
		}
		
		/// <summary> Use the targets.
		/// 
		/// The global "activator" should be set to the entity that initiated the
		/// firing.
		/// 
		/// If self.delay is set, a DelayedUse entity will be created that will
		/// actually do the SUB_UseTargets after that many seconds have passed.
		/// 
		/// Centerprints any self.message to the activator.
		/// 
		/// Search for (string)targetname in all entities that match
		/// (string)self.target and call their .use function
		/// </summary>
		
		public static void  G_UseTargets(edict_t ent, edict_t activator)
		{
			edict_t t;
			
			checkClassname(ent);
			
			// check for a delay
			if (ent.delay != 0)
			{
				// create a temp object to fire at a later time
				t = G_Spawn();
				t.classname = "DelayedUse";
				t.nextthink = GameBase.level.time + ent.delay;
				t.think = Think_Delay;
				t.activator = activator;
				if (activator == null)
					GameBase.gi.dprintf("Think_Delay with no activator\n");
				t.message = ent.message;
				t.target = ent.target;
				t.killtarget = ent.killtarget;
				return ;
			}
			
			
			// print the message
			if ((ent.message != null) && (activator.svflags & Defines.SVF_MONSTER) == 0)
			{
				GameBase.gi.centerprintf(activator, "" + ent.message);
				if (ent.noise_index != 0)
					GameBase.gi.sound(activator, Defines.CHAN_AUTO, ent.noise_index, 1, Defines.ATTN_NORM, 0);
				else
					GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0);
			}
			
			// kill killtargets
			EdictIterator edit = null;
			
			if (ent.killtarget != null)
			{
				while ((edit = GameBase.G_Find(edit, GameBase.findByTarget, ent.killtarget)) != null)
				{
					t = edit.o;
					G_FreeEdict(t);
					if (!ent.inuse)
					{
						GameBase.gi.dprintf("entity was removed while using killtargets\n");
						return ;
					}
				}
			}
			
			// fire targets
			if (ent.target != null)
			{
				edit = null;
				while ((edit = GameBase.G_Find(edit, GameBase.findByTarget, ent.target)) != null)
				{
					t = edit.o;
					// doors fire area portals in a specific way
					if (Lib.Q_stricmp("func_areaportal", t.classname) == 0 && (Lib.Q_stricmp("func_door", ent.classname) == 0 || Lib.Q_stricmp("func_door_rotating", ent.classname) == 0))
						continue;
					
					if (t == ent)
					{
						GameBase.gi.dprintf("WARNING: Entity used itself.\n");
					}
					else
					{
						if (t.use != null)
							t.use.use(t, ent, activator);
					}
					if (!ent.inuse)
					{
						GameBase.gi.dprintf("entity was removed while using targets\n");
						return ;
					}
				}
			}
		}
		
		public static void  G_InitEdict(edict_t e, int i)
		{
			e.inuse = true;
			e.classname = "noclass";
			e.gravity = 1.0f;
			//e.s.number= e - g_edicts;
			e.s = new entity_state_t(e);
			e.s.number = i;
			e.index = i;
		}
		
		/// <summary> Either finds a free edict, or allocates a new one. Try to avoid reusing
		/// an entity that was recently freed, because it can cause the client to
		/// think the entity morphed into something else instead of being removed and
		/// recreated, which can cause interpolated angles and bad trails.
		/// </summary>
		public static edict_t G_Spawn()
		{
			int i;
			edict_t e = null;
			
			//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
			for (i = (int) GameBase.maxclients.value_Renamed + 1; i < GameBase.num_edicts; i++)
			{
				e = GameBase.g_edicts[i];
				// the first couple seconds of server time can involve a lot of
				// freeing and allocating, so relax the replacement policy
				if (!e.inuse && (e.freetime < 2 || GameBase.level.time - e.freetime > 0.5))
				{
					e = GameBase.g_edicts[i] = new edict_t(i);
					G_InitEdict(e, i);
					return e;
				}
			}
			
			if (i == GameBase.game.maxentities)
				GameBase.gi.error("ED_Alloc: no free edicts");
			
			e = GameBase.g_edicts[i] = new edict_t(i);
			GameBase.num_edicts++;
			G_InitEdict(e, i);
			return e;
		}
		
		/// <summary> Marks the edict as free</summary>
		public static void  G_FreeEdict(edict_t ed)
		{
			GameBase.gi.unlinkentity(ed); // unlink from world
			
			//if ((ed - g_edicts) <= (maxclients.value + BODY_QUEUE_SIZE))
			if (ed.index <= (GameBase.maxclients.value_Renamed + Defines.BODY_QUEUE_SIZE))
			{
				// gi.dprintf("tried to free special edict\n");
				return ;
			}
			
			GameBase.g_edicts[ed.index] = new edict_t(ed.index);
			ed.classname = "freed";
			ed.freetime = GameBase.level.time;
			ed.inuse = false;
		}
		
		/// <summary> Call after linking a new trigger in during gameplay to force all entities
		/// it covers to immediately touch it.
		/// </summary>
		
		public static void  G_ClearEdict(edict_t ent)
		{
			int i = ent.index;
			GameBase.g_edicts[i] = new edict_t(i);
		}
		
		
		/// <summary> Kills all entities that would touch the proposed new positioning of ent.
		/// Ent should be unlinked before calling this!
		/// </summary>
		
		public static bool KillBox(edict_t ent)
		{
			trace_t tr;
			
			while (true)
			{
				tr = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, ent.s.origin, null, Defines.MASK_PLAYERSOLID);
				if (tr.ent == null || tr.ent == GameBase.g_edicts[0])
					break;
				
				// nail it
				GameCombat.T_Damage(tr.ent, ent, ent, Globals.vec3_origin, ent.s.origin, Globals.vec3_origin, 100000, 0, Defines.DAMAGE_NO_PROTECTION, Defines.MOD_TELEFRAG);
				
				// if we didn't kill it, fail
				if (tr.ent.solid != 0)
					return false;
			}
			
			return true; // all clear
		}
		
		/// <summary> Returns true, if two edicts are on the same team. </summary>
		public static bool OnSameTeam(edict_t ent1, edict_t ent2)
		{
			//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
			if (0 == ((int) (GameBase.dmflags.value_Renamed) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS)))
				return false;
			
			if (ClientTeam(ent1).Equals(ClientTeam(ent2)))
				return true;
			return false;
		}
		
		/// <summary> Returns the team string of an entity 
		/// with respect to rteam_by_model and team_by_skin. 
		/// </summary>
		internal static System.String ClientTeam(edict_t ent)
		{
			System.String value_Renamed;
			
			if (ent.client == null)
				return "";
			
			value_Renamed = Info.Info_ValueForKey(ent.client.pers.userinfo, "skin");
			
			int p = value_Renamed.IndexOf("/");
			
			if (p == - 1)
				return value_Renamed;
			
			//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
			if (((int) (GameBase.dmflags.value_Renamed) & Defines.DF_MODELTEAMS) != 0)
			{
				return value_Renamed.Substring(0, (p) - (0));
			}
			
			return value_Renamed.Substring(p + 1, (value_Renamed.Length) - (p + 1));
		}
		
		internal static void  ValidateSelectedItem(edict_t ent)
		{
			gclient_t cl;
			
			cl = ent.client;
			
			if (cl.pers.inventory[cl.pers.selected_item] != 0)
				return ; // valid
			
			GameItems.SelectNextItem(ent, - 1);
		}
		
		/// <summary> Returns the range catagorization of an entity reletive to self 0 melee
		/// range, will become hostile even if back is turned 1 visibility and
		/// infront, or visibility and show hostile 2 infront and show hostile 3 only
		/// triggered by damage.
		/// </summary>
		public static int range(edict_t self, edict_t other)
		{
			float[] v = new float[]{0, 0, 0};
			float len;
			
			Math3D.VectorSubtract(self.s.origin, other.s.origin, v);
			len = Math3D.VectorLength(v);
			if (len < Defines.MELEE_DISTANCE)
				return Defines.RANGE_MELEE;
			if (len < 500)
				return Defines.RANGE_NEAR;
			if (len < 1000)
				return Defines.RANGE_MID;
			return Defines.RANGE_FAR;
		}
		
		internal static void  AttackFinished(edict_t self, float time)
		{
			self.monsterinfo.attack_finished = GameBase.level.time + time;
		}
		
		/// <summary> Returns true if the entity is in front (in sight) of self</summary>
		public static bool infront(edict_t self, edict_t other)
		{
			float[] vec = new float[]{0, 0, 0};
			float dot;
			float[] forward = new float[]{0, 0, 0};
			
			Math3D.AngleVectors(self.s.angles, forward, null, null);
			Math3D.VectorSubtract(other.s.origin, self.s.origin, vec);
			Math3D.VectorNormalize(vec);
			dot = Math3D.DotProduct(vec, forward);
			
			if (dot > 0.3)
				return true;
			return false;
		}
		
		/// <summary> Returns 1 if the entity is visible to self, even if not infront().</summary>
		public static bool visible(edict_t self, edict_t other)
		{
			float[] spot1 = new float[]{0, 0, 0};
			float[] spot2 = new float[]{0, 0, 0};
			trace_t trace;
			
			Math3D.VectorCopy(self.s.origin, spot1);
			spot1[2] += self.viewheight;
			Math3D.VectorCopy(other.s.origin, spot2);
			spot2[2] += other.viewheight;
			trace = GameBase.gi.trace(spot1, Globals.vec3_origin, Globals.vec3_origin, spot2, self, Defines.MASK_OPAQUE);
			
			if (trace.fraction == 1.0)
				return true;
			return false;
		}
		
		/// <summary> Finds a target.
		/// 
		/// Self is currently not attacking anything, so try to find a target
		/// 
		/// Returns TRUE if an enemy was sighted
		/// 
		/// When a player fires a missile, the point of impact becomes a fakeplayer
		/// so that monsters that see the impact will respond as if they had seen the
		/// player.
		/// 
		/// To avoid spending too much time, only a single client (or fakeclient) is
		/// checked each frame. This means multi player games will have slightly
		/// slower noticing monsters.
		/// </summary>
		internal static bool FindTarget(edict_t self)
		{
			edict_t client;
			bool heardit;
			int r;
			
			if ((self.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0)
			{
				if (self.goalentity != null && self.goalentity.inuse && self.goalentity.classname != null)
				{
					if (self.goalentity.classname.Equals("target_actor"))
						return false;
				}
				
				//FIXME look for monsters?
				return false;
			}
			
			// if we're going to a combat point, just proceed
			if ((self.monsterinfo.aiflags & Defines.AI_COMBAT_POINT) != 0)
				return false;
			
			// if the first spawnflag bit is set, the monster will only wake up on
			// really seeing the player, not another monster getting angry or
			// hearing something
			// revised behavior so they will wake up if they "see" a player make a
			// noise but not weapon impact/explosion noises
			
			heardit = false;
			if ((GameBase.level.sight_entity_framenum >= (GameBase.level.framenum - 1)) && 0 == (self.spawnflags & 1))
			{
				client = GameBase.level.sight_entity;
				if (client.enemy == self.enemy)
					return false;
			}
			else if (GameBase.level.sound_entity_framenum >= (GameBase.level.framenum - 1))
			{
				client = GameBase.level.sound_entity;
				heardit = true;
			}
			else if (null != (self.enemy) && (GameBase.level.sound2_entity_framenum >= (GameBase.level.framenum - 1)) && 0 != (self.spawnflags & 1))
			{
				client = GameBase.level.sound2_entity;
				heardit = true;
			}
			else
			{
				client = GameBase.level.sight_client;
				if (client == null)
					return false; // no clients to get mad at
			}
			
			// if the entity went away, forget it
			if (!client.inuse)
				return false;
			
			if (client.client != null)
			{
				if ((client.flags & Defines.FL_NOTARGET) != 0)
					return false;
			}
			else if ((client.svflags & Defines.SVF_MONSTER) != 0)
			{
				if (client.enemy == null)
					return false;
				if ((client.enemy.flags & Defines.FL_NOTARGET) != 0)
					return false;
			}
			else if (heardit)
			{
				if ((client.owner.flags & Defines.FL_NOTARGET) != 0)
					return false;
			}
			else
				return false;
			
			if (!heardit)
			{
				r = range(self, client);
				
				if (r == Defines.RANGE_FAR)
					return false;
				
				// this is where we would check invisibility
				// is client in an spot too dark to be seen?
				
				if (client.light_level <= 5)
					return false;
				
				if (!visible(self, client))
					return false;
				
				
				if (r == Defines.RANGE_NEAR)
				{
					if (client.show_hostile < GameBase.level.time && !infront(self, client))
						return false;
				}
				else if (r == Defines.RANGE_MID)
				{
					if (!infront(self, client))
						return false;
				}
				
				if (client == self.enemy)
					return true; // JDC false;
				
				self.enemy = client;
				
				if (!self.enemy.classname.Equals("player_noise"))
				{
					self.monsterinfo.aiflags &= ~ Defines.AI_SOUND_TARGET;
					
					if (self.enemy.client == null)
					{
						self.enemy = self.enemy.enemy;
						if (self.enemy.client == null)
						{
							self.enemy = null;
							return false;
						}
					}
				}
			}
			else
			{
				// heard it
				float[] temp = new float[]{0, 0, 0};
				
				if ((self.spawnflags & 1) != 0)
				{
					if (!visible(self, client))
						return false;
				}
				else
				{
					if (!GameBase.gi.inPHS(self.s.origin, client.s.origin))
						return false;
				}
				
				Math3D.VectorSubtract(client.s.origin, self.s.origin, temp);
				
				if (Math3D.VectorLength(temp) > 1000)
				// too far to hear
					return false;
				
				
				// check area portals - if they are different and not connected then
				// we can't hear it
				if (client.areanum != self.areanum)
					if (!GameBase.gi.AreasConnected(self.areanum, client.areanum))
						return false;
				
				self.ideal_yaw = Math3D.vectoyaw(temp);
				M.M_ChangeYaw(self);
				
				// hunt the sound for a bit; hopefully find the real player
				self.monsterinfo.aiflags |= Defines.AI_SOUND_TARGET;
				
				if (client == self.enemy)
					return true; // JDC false;
				
				self.enemy = client;
			}
			
			// got one
			FoundTarget(self);
			
			if (0 == (self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) && (self.monsterinfo.sight != null))
				self.monsterinfo.sight.interact(self, self.enemy);
			
			return true;
		}
		
		public static void  FoundTarget(edict_t self)
		{
			// let other monsters see this monster for a while
			if (self.enemy.client != null)
			{
				GameBase.level.sight_entity = self;
				GameBase.level.sight_entity_framenum = GameBase.level.framenum;
				GameBase.level.sight_entity.light_level = 128;
			}
			
			//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
			self.show_hostile = (int) GameBase.level.time + 1; // wake up other
			// monsters
			
			Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
			self.monsterinfo.trail_time = GameBase.level.time;
			
			if (self.combattarget == null)
			{
				GameAI.HuntTarget(self);
				return ;
			}
			
			self.goalentity = self.movetarget = GameBase.G_PickTarget(self.combattarget);
			if (self.movetarget == null)
			{
				self.goalentity = self.movetarget = self.enemy;
				GameAI.HuntTarget(self);
				GameBase.gi.dprintf("" + self.classname + "at " + Lib.vtos(self.s.origin) + ", combattarget " + self.combattarget + " not found\n");
				return ;
			}
			
			// clear out our combattarget, these are a one shot deal
			self.combattarget = null;
			self.monsterinfo.aiflags |= Defines.AI_COMBAT_POINT;
			
			// clear the targetname, that point is ours!
			self.movetarget.targetname = null;
			self.monsterinfo.pausetime = 0;
			
			// run for it
			self.monsterinfo.run.think(self);
		}
		
		//UPGRADE_NOTE: The initialization of  'Think_Delay' was moved to static method 'jake2.game.GameUtil'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		public static EntThinkAdapter Think_Delay;
		
		//UPGRADE_NOTE: The initialization of  'G_FreeEdictA' was moved to static method 'jake2.game.GameUtil'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		public static EntThinkAdapter G_FreeEdictA;
		
		//UPGRADE_NOTE: The initialization of  'MegaHealth_think' was moved to static method 'jake2.game.GameUtil'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		internal static EntThinkAdapter MegaHealth_think;
		
		
		//UPGRADE_NOTE: The initialization of  'M_CheckAttack' was moved to static method 'jake2.game.GameUtil'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		public static EntThinkAdapter M_CheckAttack;
		
		//UPGRADE_NOTE: The initialization of  'monster_use' was moved to static method 'jake2.game.GameUtil'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		internal static EntUseAdapter monster_use;
		static GameUtil()
		{
			Think_Delay = new AnonymousClassEntThinkAdapter();
			G_FreeEdictA = new AnonymousClassEntThinkAdapter1();
			MegaHealth_think = new AnonymousClassEntThinkAdapter2();
			M_CheckAttack = new AnonymousClassEntThinkAdapter3();
			monster_use = new AnonymousClassEntUseAdapter();
		}
	}
}